import java.io.*;
import java.text.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

import java.awt.geom.Point2D;
import java.awt.geom.Point2D;
import java.lang.Math;

/**
 * My test servlet
 *
 * @author Liz Warner
 */

public class MWN extends HttpServlet {

	private Hashtable<String,Bus> busses = null;
	private Hashtable<String,ArrayList<String>> routes = null;
	private boolean setup = false;
	private Timer timer = null;
    public void doGet(HttpServletRequest request,
                      HttpServletResponse response)
        throws IOException, ServletException
    {
    	if(!setup) {
    		busses = new Hashtable<String,Bus>();
    		//populate busses
    		Bus b1 = new Bus( "b1" , "/Users/lukehaub/Uni/mwnandroidbus/server/simulator/116.route" , "116" );
			Bus b2 = new Bus( "b2" , "/Users/lukehaub/Uni/mwnandroidbus/server/simulator/117.route" , "117" );
			Bus b3 = new Bus( "b3" , "/Users/lukehaub/Uni/mwnandroidbus/server/simulator/99C.route" , "99C" );
			Bus b4 = new Bus( "b4" , "/Users/lukehaub/Uni/mwnandroidbus/server/simulator/99B.route" , "99B" );
			
			//some later busses
    		Bus b12 = new Bus( "b1" , "/Users/lukehaub/Uni/mwnandroidbus/server/simulator/116.route" , "116" );
			Bus b22 = new Bus( "b2" , "/Users/lukehaub/Uni/mwnandroidbus/server/simulator/117.route" , "117" );
			Bus b32 = new Bus( "b3" , "/Users/lukehaub/Uni/mwnandroidbus/server/simulator/99C.route" , "99C" );
			Bus b42 = new Bus( "b4" , "/Users/lukehaub/Uni/mwnandroidbus/server/simulator/99B.route" , "99B" );
			
			for(int i=0; i<100; i++) {
				b12.step();
				b22.step();
				b32.step();
				b42.step();
			}

			routes = loadRouteData();
		
			busses.put("116",b1);
			busses.put("117",b2);
			busses.put("99C",b3);
			busses.put("99B",b4);

			busses.put("1162",b12);
			busses.put("1172",b22);
			busses.put("99C2",b32);
			busses.put("99B2",b42);

			timer = new Timer(); 
			timer.scheduleAtFixedRate ( new TimerTask() { 
				public void run() {
					Enumeration<Bus> e = busses.elements();
					while(e.hasMoreElements()) {
						Bus bb = e.nextElement();
						bb.step();
					}
					//busses.get("116").step();
					//busses.get("117").step();
				}
			}, 0, 1000);
			setup = true;
    	}
    	
		String qs = request.getParameter("routes");
		if (qs != null) {
			if(qs.equals("yes")) {
				Enumeration<ArrayList<String>> e = routes.elements();
				response.setContentType("text/html");
				PrintWriter out = response.getWriter();
				out.println("<html>");
				out.println("<head>");
				out.println("<title>Routes</title>");
				out.println("</head>");
				out.println("<body bgcolor=\"white\">");
				while(e.hasMoreElements()) {
					out.print("ROUTE:");					
					ArrayList<String> a = e.nextElement();
					for(int index=0; index<a.size(); index++) {
						out.println(a.get(index));
					}
				}
				out.println("</body>");
				out.println("</html>");
				return;
			}
		}
    	
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("<html>");
        out.println("<head>");
        out.println("<title>Location</title>");
        out.println("</head>");
        out.println("<body bgcolor=\"white\">");
		Enumeration<Bus> e = busses.elements();
		while(e.hasMoreElements()) {
			Bus bb = e.nextElement();
			out.println("<h1> "+bb.routeNum+" X:"+bb.x+" Y:"+bb.y+" </h1>");
		}
        //out.println("<h1> 116 X:"+busses.get(116).x+" Y:"+busses.get(116).y+" </h1>");
        //out.println("<h1> 117 X:"+busses.get(117).x+" Y:"+busses.get(117).y+" </h1>");
        out.println("</body>");
        out.println("</html>");
    }

	private Hashtable<String,ArrayList<String>> loadRouteData() {
		Hashtable<String,ArrayList<String>> r = new Hashtable<String,ArrayList<String>>();
		String line = "";
		String line2 = "";
		try {
			BufferedReader br = new BufferedReader(new FileReader( "/Users/lukehaub/Uni/mwnandroidbus/server/simulator/Routes.txt" ));
			while ((line = br.readLine()) != null) {
				BufferedReader br2 = new BufferedReader(new FileReader( "/Users/lukehaub/Uni/mwnandroidbus/server/simulator/"+line ));
				ArrayList<String> a = new ArrayList<String>();
				a.add(line);
				while((line2 = br2.readLine()) != null) { 
					a.add(line2);
				}
				r.put(line,a);
			}			
		}catch(Exception e) {
			System.out.println("Died: " + e);
		}		
		return r;
	}

	class Bus{
		
		ArrayList<Point2D.Double> route;
		double busSpeed; //dist per step period, in coord units
		int stops; //how many steps between stops
		int wait; //how many steps to wait at stop
		String id;
		double x;
		double y;
		int nextTargetPoint; //point in route currently driving to;
		Random rand;
		int stopOffset; //random number (up to half number of steps between stops) added to stop counter so buses dont all stop at same time
		int state; //bus is state machine.  0 = driving, 1+ = stopped at stop
		int stopCount; //counts num of steps stopped picking up and steps driving
		String routeNum;
		
		public Bus( String id , String routefile , String rn ){
			routeNum = rn;
			state = 0;
			stopCount = 0;
			rand = new Random();
			route = new ArrayList<Point2D.Double>();
			busSpeed = 0.0001;
			stops = 12; //60
			wait = 3; //30
			stopOffset = rand.nextInt(stops/2);
			this.id = id;
			nextTargetPoint = 1; //start buss at point 0
			
					
			loadRoute( routefile );
			
			x = route.get(0).getX();
			y = route.get(0).getY();
		}//cstrcr
		
		public void step(){
			
			switch (state) {
			
				case 0:{//driving
					double distance = 0;
					Point2D.Double target = route.get( nextTargetPoint );
					double distToTarget = target.distance( x , y );
					
					if (distToTarget < busSpeed){ //split by point			
						x = target.getX();		
						y = target.getY();	
						distance = busSpeed - distToTarget;			
						nextTargetPoint++;
						if (nextTargetPoint >= route.size()){
							nextTargetPoint = 0;
						}			
						target = route.get( nextTargetPoint );
						distToTarget = target.distance( x , y );
					}
					else{ //normal, not split by point
						distance = busSpeed;
					}
					
					//alternative location calc: get distance from her to target, calculate what percentage will need to move, then increase x and y by that percentage
					
					double angle = Math.asin(   ( target.getX()-x ) / distToTarget   );
					double angle2 = Math.acos(   ( target.getY()-y ) / distToTarget   );
							
					x += Math.sin(angle) * distance;
					y += Math.cos(angle2) * distance;
					
					stopCount++;
					if ( (stopCount+stopOffset) % stops == 0 ) {
						stopCount = 0;
						state = 1;
					}
				}//case 0 driving
				
				case 1:{//stopped
					stopCount++;
					if (stopCount >= wait){
						stopCount = 0;
						state = 0;
					}
				}//case 1 stopped
			
			}//switch
			//System.out.println( id + " " + x + " " + y + " " + routeNum );	
		}//step
		
		
		
		
		public void loadRoute(String routeFile){ //note not tolerant of errors in route file, so dont make any ;)
			
			String line; 
	
			try {
				BufferedReader br = new BufferedReader(new FileReader( routeFile ));
				while ((line = br.readLine()) != null) { 
									
					StringTokenizer st = new StringTokenizer(line);
					double x =  Double.valueOf( st.nextToken() ).doubleValue();
					double y =  Double.valueOf( st.nextToken() ).doubleValue();
					
					route.add( new Point2D.Double(x,y) );
				
				} 
			}catch(Exception e) {
				System.out.println("Died: " + e);
			}		
			
		}//loadrout
	
	}

}
